//! # 远程配置获取器
//!
//! 提供从配置服务器获取配置的HTTP客户端实现，支持多服务器、
//! 重试机制、连接池等企业级特性。
//!
//! ## 核心功能
//!
//! * **HTTP客户端** - 基于reqwest的异步HTTP客户端
//! * **多服务器支持** - 支持配置多个服务器进行故障转移
//! * **重试机制** - 指数退避重试策略
//! * **连接池** - HTTP连接池复用
//! * **认证支持** - JWT Token认证
//! * **健康检查** - 服务器健康状态检查

use std::time::Duration;
use std::collections::HashMap;
use std::time::SystemTime;

use async_trait::async_trait;
use reqwest::{Client, Response};
use serde_json::Value;
use tracing::{debug, error, info, warn};
use rustcloud_core::http_client::{HttpClientConfig, HttpClientFactory};

use crate::RustCloudConfig;
use crate::core::{ConfigurationProvider, ConfigurationData, ConfigurationResult};
use super::{
    ConfigClientConfig, ConfigEnvironment, RemoteConfigFetcher, ConfigClientError, ClientResult,
};

/// HTTP配置获取器
pub struct HttpConfigFetcher {
    /// HTTP客户端
    client: Client,
    /// 服务器URL列表
    server_urls: Vec<String>,
    /// 当前服务器索引
    current_server_index: std::sync::atomic::AtomicUsize,
    /// 客户端配置
    config: ConfigClientConfig,
}

impl HttpConfigFetcher {
    /// 创建新的HTTP配置获取器（使用统一的工厂方法）
    pub fn new(config: &ConfigClientConfig) -> ClientResult<Self> {
        // 使用 rustcloud-core 的配置构建器创建 HTTP 客户端配置
        let http_config = HttpClientConfig::builder()
            .timeout(config.read_timeout)
            .connect_timeout(config.connect_timeout)
            .user_agent("RustCloud-Config-Client/1.0".to_string())
            .build()
            .map_err(|e| ConfigClientError::ConfigurationError(e))?;

        // 使用统一的工厂方法创建客户端
        let client = HttpClientFactory::create_reqwest_client(&http_config)?;

        Ok(Self {
            client,
            server_urls: config.server_urls.clone(),
            current_server_index: std::sync::atomic::AtomicUsize::new(0),
            config: config.clone(),
        })
    }

    /// 获取当前服务器URL
    fn get_current_server_url(&self) -> &str {
        let index = self.current_server_index.load(std::sync::atomic::Ordering::Relaxed);
        &self.server_urls[index % self.server_urls.len()]
    }

    /// 切换到下一个服务器
    fn switch_to_next_server(&self) {
        self.current_server_index.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
        warn!("🔄 切换到下一个配置服务器");
    }

    /// 构建配置URL
    fn build_config_url(&self, environment: &ConfigEnvironment) -> String {
        format!(
            "{}/{}/{}/{}",
            self.get_current_server_url().trim_end_matches('/'),
            environment.application,
            environment.profile,
            environment.label
        )
    }

    /// 构建健康检查URL
    fn build_health_url(&self) -> String {
        format!("{}/health", self.get_current_server_url().trim_end_matches('/'))
    }

    /// 构建版本URL
    fn build_version_url(&self, environment: &ConfigEnvironment) -> String {
        format!(
            "{}/{}/{}/{}/version",
            self.get_current_server_url().trim_end_matches('/'),
            environment.application,
            environment.profile,
            environment.label
        )
    }

    /// 发送HTTP请求（带重试）
    async fn send_request_with_retry<F, Fut>(&self, request_fn: F) -> ClientResult<Response>
    where
        F: Fn() -> Fut + Clone,
        Fut: std::future::Future<Output = Result<Response, reqwest::Error>>,
    {
        let mut last_error = None;
        let mut retry_delay = self.config.retry_interval;

        for attempt in 0..=self.config.retry_count {
            // 尝试每个服务器
            for server_attempt in 0..self.server_urls.len() {
                match request_fn().await {
                    Ok(response) => {
                        if response.status().is_success() {
                            return Ok(response);
                        } else {
                            let status = response.status();
                            let error_text = response.text().await.unwrap_or_default();
                            last_error = Some(ConfigClientError::ServerConnectionError(
                                format!("HTTP {}: {}", status, error_text)
                            ));
                        }
                    }
                    Err(e) => {
                        last_error = Some(ConfigClientError::HttpError { source: e });
                    }
                }

                // 如果不是最后一个服务器，切换到下一个
                if server_attempt < self.server_urls.len() - 1 {
                    self.switch_to_next_server();
                }
            }

            // 如果不是最后一次重试，等待后重试
            if attempt < self.config.retry_count {
                warn!("⏰ 第 {} 次重试失败，等待 {:?} 后重试", attempt + 1, retry_delay);
                tokio::time::sleep(retry_delay).await;
                retry_delay = std::cmp::min(retry_delay * 2, Duration::from_secs(30)); // 指数退避，最大30秒
            }
        }

        Err(last_error.unwrap_or_else(|| {
            ConfigClientError::ServerConnectionError("所有重试都失败".to_string())
        }))
    }

    /// 添加认证头
    fn add_auth_header(&self, request: reqwest::RequestBuilder) -> reqwest::RequestBuilder {
        if let Some(token) = &self.config.auth_token {
            request.header("Authorization", format!("Bearer {}", token))
        } else {
            request
        }
    }

    /// 解析配置响应
    async fn parse_config_response(&self, response: Response) -> ClientResult<RustCloudConfig> {
        let content_type = response.headers()
            .get("content-type")
            .and_then(|v| v.to_str().ok())
            .unwrap_or("application/json")
            .to_string(); // 克隆字符串以避免借用问题

        let text = response.text().await
            .map_err(|e| ConfigClientError::HttpError { source: e })?;

        if content_type.contains("application/json") {
            // 处理JSON响应（Spring Cloud Config格式）
            let json_value: Value = serde_json::from_str(&text)
                .map_err(|e| ConfigClientError::SerializationError { source: e })?;

            // 如果是Spring Cloud Config格式，需要转换
            if let Some(property_sources) = json_value.get("propertySources") {
                self.convert_spring_cloud_format(property_sources).await
            } else {
                // 直接的配置格式
                serde_json::from_str(&text)
                    .map_err(|e| ConfigClientError::SerializationError { source: e })
            }
        } else if content_type.contains("application/yaml") || content_type.contains("text/yaml") {
            // 处理YAML响应
            serde_yaml::from_str(&text)
                .map_err(|e| ConfigClientError::SerializationError {
                    source: serde_json::Error::io(std::io::Error::new(std::io::ErrorKind::InvalidData, e.to_string()))
                })
        } else if content_type.contains("application/toml") {
            // 处理TOML响应
            toml::from_str(&text)
                .map_err(|e| ConfigClientError::SerializationError {
                    source: serde_json::Error::io(std::io::Error::new(std::io::ErrorKind::InvalidData, e.to_string()))
                })
        } else {
            Err(ConfigClientError::ConfigFetchError(
                format!("不支持的响应格式: {}", content_type)
            ))
        }
    }

    /// 转换Spring Cloud Config格式
    async fn convert_spring_cloud_format(&self, property_sources: &Value) -> ClientResult<RustCloudConfig> {
        if let Some(sources) = property_sources.as_array() {
            // 合并所有属性源
            let mut merged_config = RustCloudConfig::default();
            
            for source in sources {
                if let Some(source_obj) = source.get("source") {
                    // 这里需要将扁平化的属性转换为嵌套的配置结构
                    // 暂时使用简单的转换逻辑
                    if let Ok(config_part) = serde_json::from_value::<RustCloudConfig>(source_obj.clone()) {
                        // 简单的合并逻辑，实际应该更复杂
                        merged_config = config_part;
                    }
                }
            }
            
            Ok(merged_config)
        } else {
            Err(ConfigClientError::ConfigFetchError(
                "无效的Spring Cloud Config响应格式".to_string()
            ))
        }
    }
}

#[async_trait]
impl ConfigurationProvider for HttpConfigFetcher {
    async fn get_configuration(&self, environment: &ConfigEnvironment) -> ConfigurationResult<ConfigurationData> {
        let config = self.fetch_config(environment).await
            .map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>)?;
        
        let data = ConfigurationData {
            environment: environment.clone(),
            config,
            version: "remote".to_string(),
            last_modified: SystemTime::now(),
            source: "http_remote".to_string(),
            properties: HashMap::new(),
        };
        
        Ok(data)
    }
    
    async fn exists(&self, environment: &ConfigEnvironment) -> ConfigurationResult<bool> {
        match self.get_version(environment).await {
            Ok(_) => Ok(true),
            Err(_) => Ok(false),
        }
    }
    
    async fn list_applications(&self) -> ConfigurationResult<Vec<String>> {
        // HTTP获取器通常不支持列举应用，返回空列表
        Ok(vec![])
    }
    
    async fn list_profiles(&self, _application: &str) -> ConfigurationResult<Vec<String>> {
        // HTTP获取器通常不支持列举环境，返回空列表
        Ok(vec![])
    }
    
    async fn list_labels(&self, _application: &str, _profile: &str) -> ConfigurationResult<Vec<String>> {
        // HTTP获取器通常不支持列举标签，返回空列表
        Ok(vec![])
    }
}

#[async_trait]
impl RemoteConfigFetcher for HttpConfigFetcher {
    async fn fetch_config(&self, environment: &ConfigEnvironment) -> ClientResult<RustCloudConfig> {
        debug!("📡 从远程获取配置: {}:{}:{}", 
            environment.application, environment.profile, environment.label);

        let url = self.build_config_url(environment);
        debug!("🌐 请求URL: {}", url);

        let response = self.send_request_with_retry(|| {
            let request = self.client.get(&url);
            let request = self.add_auth_header(request);
            request.send()
        }).await?;

        debug!("✅ 收到配置响应，状态码: {}", response.status());

        let config = self.parse_config_response(response).await?;

        info!("📖 配置获取成功: {}:{}:{}", 
            environment.application, environment.profile, environment.label);

        Ok(config)
    }

    async fn health_check(&self) -> ClientResult<bool> {
        debug!("🏥 检查服务器健康状态");

        let url = self.build_health_url();
        debug!("🌐 健康检查URL: {}", url);

        match self.send_request_with_retry(|| {
            let request = self.client.get(&url);
            let request = self.add_auth_header(request);
            request.send()
        }).await {
            Ok(response) => {
                let is_healthy = response.status().is_success();
                
                if is_healthy {
                    debug!("✅ 服务器健康状态正常");
                } else {
                    warn!("⚠️ 服务器健康状态异常: {}", response.status());
                }
                
                Ok(is_healthy)
            }
            Err(e) => {
                error!("❌ 健康检查失败: {}", e);
                Ok(false)
            }
        }
    }

    async fn get_version(&self, environment: &ConfigEnvironment) -> ClientResult<String> {
        debug!("🔍 获取配置版本: {}:{}:{}", 
            environment.application, environment.profile, environment.label);

        // 首先尝试专用的版本端点
        let version_url = self.build_version_url(environment);
        
        match self.send_request_with_retry(|| {
            let request = self.client.get(&version_url);
            let request = self.add_auth_header(request);
            request.send()
        }).await {
            Ok(response) => {
                let version_text = response.text().await?;
                
                debug!("📋 获取到版本信息: {}", version_text);
                Ok(version_text.trim().to_string())
            }
            Err(_) => {
                // 如果版本端点不可用，从配置响应中提取版本信息
                debug!("⚠️ 版本端点不可用，从配置响应中提取版本");
                
                let config_url = self.build_config_url(environment);
                let response = self.send_request_with_retry(|| {
                    let request = self.client.get(&config_url);
                    let request = self.add_auth_header(request);
                    request.send()
                }).await?;

                let text = response.text().await?;

                // 尝试从JSON响应中提取版本
                if let Ok(json) = serde_json::from_str::<Value>(&text) {
                    if let Some(version) = json.get("version") {
                        if let Some(version_str) = version.as_str() {
                            return Ok(version_str.to_string());
                        }
                    }
                }

                // 如果无法提取版本，返回时间戳作为版本
                let timestamp = std::time::SystemTime::now()
                    .duration_since(std::time::UNIX_EPOCH)
                    .unwrap_or_default()
                    .as_secs();
                Ok(timestamp.to_string())
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[tokio::test]
    async fn test_http_fetcher_creation() {
        let config = ConfigClientConfig {
            server_urls: vec!["http://localhost:8888".to_string()],
            ..Default::default()
        };

        let fetcher = HttpConfigFetcher::new(&config);
        assert!(fetcher.is_ok());
    }

    #[tokio::test]
    async fn test_url_building() {
        let config = ConfigClientConfig {
            server_urls: vec!["http://localhost:8888".to_string()],
            ..Default::default()
        };

        let fetcher = HttpConfigFetcher::new(&config).unwrap();
        let environment = ConfigEnvironment {
            application: "test-app".to_string(),
            profile: "dev".to_string(),
            label: "main".to_string(),
            version: None,
            state: None,
        };

        let url = fetcher.build_config_url(&environment);
        assert_eq!(url, "http://localhost:8888/test-app/dev/main");

        let health_url = fetcher.build_health_url();
        assert_eq!(health_url, "http://localhost:8888/health");
    }

    #[tokio::test]
    async fn test_server_switching() {
        let config = ConfigClientConfig {
            server_urls: vec![
                "http://server1:8888".to_string(),
                "http://server2:8888".to_string(),
            ],
            ..Default::default()
        };

        let fetcher = HttpConfigFetcher::new(&config).unwrap();
        
        assert_eq!(fetcher.get_current_server_url(), "http://server1:8888");
        
        fetcher.switch_to_next_server();
        assert_eq!(fetcher.get_current_server_url(), "http://server2:8888");
        
        fetcher.switch_to_next_server();
        assert_eq!(fetcher.get_current_server_url(), "http://server1:8888"); // 循环回第一个
    }
}